package com.itbaizhan.service;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.itbaizhan.domain.CancelLog;
import com.itbaizhan.domain.ConfirmLog;
import com.itbaizhan.domain.TryLog;
import com.itbaizhan.domain.UserAccount;
import com.itbaizhan.dto.UserAccountDTO;
import com.itbaizhan.mapper.CancelLogMapper;
import com.itbaizhan.mapper.ConfirmLogMapper;
import com.itbaizhan.mapper.TryLogMapper;
import com.itbaizhan.mapper.UserAccountMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboService;
import org.dromara.hmily.annotation.HmilyTCC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Date;

/**
 * @author spf
 * @date 2024/4/18
 * @time 15:28
 */

@DubboService(version = "1.0.0")
@Component
@Slf4j
public class UserAccountServiceImpl implements UserAccountService {

    @Autowired
    private UserAccountMapper userAccountMapper;
    @Autowired
    private TryLogMapper tryLogMapper;
    @Autowired
    private ConfirmLogMapper confirmLogMapper;
    @Autowired
    private CancelLogMapper cancelLogMapper;


    @Override
    @HmilyTCC(confirmMethod = "sayConfirm", cancelMethod = "sayCancel")
    // 解决幂等性问题。建立三种日志保存事务，每次操作之前或者是之后都保存日志，就会解决接口幂等性问题
    public void transfer(UserAccountDTO userAccountDTO) {
        // 接口幂等性
        String txNo = userAccountDTO.getTxNo();
        log.info("**********  执行bank01 的 Try方法 ，事务id={}",txNo);
        TryLog tryLog = tryLogMapper.selectById(txNo);
        if (tryLog != null){
            return;
        }
        if(confirmLogMapper.selectById(txNo) != null || cancelLogMapper.selectById(txNo) != null){
            return;
        }
        // 查询账户
        UserAccount userAccount = userAccountMapper.selectById(userAccountDTO.getAccountNo2());
        if (userAccount != null){
            LambdaUpdateWrapper<UserAccount> ulw = new LambdaUpdateWrapper<>();
            ulw.set(UserAccount::getTransferAmount,userAccount.getTransferAmount().add(userAccountDTO.getAccountBalance()));
            ulw.eq(UserAccount::getAccountNo,userAccountDTO.getAccountNo2());
            userAccountMapper.update(userAccount,ulw);
        }

        // 新增日志
        TryLog tryLog1 = new TryLog();
        tryLog1.setTxNo(txNo);
        tryLog1.setCreateTime(new Date());
        tryLogMapper.insert(tryLog1);
        System.out.println("b2try阶段");
    }

    public void sayConfirm(UserAccountDTO userAccountDTO){
        String txNo = userAccountDTO.getTxNo();
        log.info("**********  执行bank02 的 Confrim方法 ，事务id={}",txNo);

        ConfirmLog confirmLog = confirmLogMapper.selectById(txNo);
        if (confirmLog!=null){
            return;
        }

        UserAccount userAccount = userAccountMapper.selectById(userAccountDTO.getAccountNo2());
        userAccount.setAccountBalance(userAccount.getAccountBalance().add(userAccountDTO.getAccountBalance()));
        userAccount.setTransferAmount(userAccount.getTransferAmount().subtract(userAccountDTO.getAccountBalance()));
        userAccountMapper.updateById(userAccount);

        ConfirmLog confirmLog1 = new ConfirmLog();
        confirmLog1.setTxNo(txNo);
        confirmLog1.setCreateTime(new Date());
        confirmLogMapper.insert(confirmLog1);


        System.out.println("b2确认阶段");
    }

    public void sayCancel(UserAccountDTO userAccountDTO){

        String txNo = userAccountDTO.getTxNo();
        log.info("**********  执行bank02 的 Cancel方法 ，事务id={}",txNo);

        CancelLog cancelLog = cancelLogMapper.selectById(txNo);
        if (cancelLog!=null){
            return;
        }

        UserAccount userAccount = userAccountMapper.selectById(userAccountDTO.getAccountNo2());
        userAccount.setTransferAmount(userAccount.getTransferAmount().subtract(userAccountDTO.getAccountBalance()));
        userAccountMapper.updateById(userAccount);

        CancelLog cancelLog1 = new CancelLog();
        cancelLog1.setTxNo(txNo);
        cancelLog1.setCreateTime(new Date());
        cancelLogMapper.insert(cancelLog1);

        System.out.println("b2cancel阶段");
    }
}
